package com.hd123.rumba.action.qt;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.servlet.http.HttpServletResponse;

import net.sf.hibernate.HibernateException;

import org.apache.log4j.Logger;
import org.apache.log4j.lf5.util.StreamUtils;

import com.hd123.rumba.qt.MaxQueryException;
import com.hd123.rumba.qt.QTConstants;
import com.hd123.rumba.qt.QueryResultSession;
import com.hd123.rumba.qt.def.IQueryDef;
import com.hd123.rumba.qt.def.IQueryDefinitionMgr;
import com.hd123.rumba.qt.def.QueryDefinition;
import com.hd123.rumba.qt.def.SQLOrder;
import com.hd123.rumba.qt.result.IQueryResultMgr;
import com.hd123.rumba.qt.result.QueryResultDescription;
import com.hd123.rumba.request.Action;
import com.hd123.rumba.request.ActionAbstractImpl;
import com.hd123.rumba.request.ActionConstants;
import com.hd123.rumba.request.FileTooLargeException;
import com.hd123.rumba.request.JspLib;
import com.hd123.rumba.runtime.NamingMgr;
import com.hd123.rumba.sql.SQLSubquery;
import com.hd123.rumba.util.MidasUtil;
import com.hd123.rumba.util.StringUtil;

public class RptServer extends ActionAbstractImpl implements Action {

  public String execute() throws Exception {
    String startnode = (String) dd.getFormValue("start");
    String url = ActionConstants.NOTIMPLEMENTED;
    if (startnode == null)
      throw new Exception("start未定义!");
    if (startnode.equals("getData"))
      url = executeWithPermission("getData", null);
    else if (startnode.equals("getReport"))
      url = executeWithPermission("getReport", null);
    else if (startnode.equals("saveReport")) {
      try {
        dd.prepareMultipartRequest(0x200000);
      } catch (FileTooLargeException e) {
        dd.addErrorText("文件大小超出了限制值" + 0x20000);
        return ActionConstants.FILETOOLARGE;
      }
      url = executeWithPermission("saveReport", ViewQuery.PERMISSION_FR3REPORTDESIGN);
    }
    return url;
  }

  /**
   * 返回报表文件. get startnode=getReport&qrdUuid=xxx. <br>
   * 报表文件是和查询文件同一目录下同名的后缀为.fr3的文件
   * 
   * @return
   * @throws Exception
   */
  public String getReport() throws Exception {
    IQueryResultMgr qrm = (IQueryResultMgr) NamingMgr.getInstance()
        .lookupMgr(IQueryResultMgr.class);
    String qrdUuid = (String) dd.getFormValue("qrdUuid");
    QueryResultDescription qrd = (QueryResultDescription) qrm.findQrdByUuid(qrdUuid);
    String fileName = qrd.getQdName().replace(".sql", ".fr3");
    File file = new File(QTConstants.QDHOME, fileName);
    sendFile(dd.getResponse(), file);
    return ActionConstants.DIRECT;
  }

  /**
   * 保存报表文件. post startnode=saveReport&qrdUuid=xxx formvalue: filename=xxx
   * 
   * @return
   * @throws Exception
   */
  public String saveReport() throws Exception {
    IQueryResultMgr qrm = (IQueryResultMgr) NamingMgr.getInstance()
        .lookupMgr(IQueryResultMgr.class);
    IQueryDefinitionMgr qdm = (IQueryDefinitionMgr) NamingMgr.getInstance().lookupMgr(
        IQueryDefinitionMgr.class);
    PrintWriter out = dd.getResponse().getWriter();
    try {
      String qrdUuid = (String) dd.getFormValue("qrdUuid");
      QueryResultDescription qrd = (QueryResultDescription) qrm.findQrdByUuid(qrdUuid);
      if (qrd != null) {
        IQueryDef queryDef = qdm.getQueryDef(qrd.getQdUuid());
        if (queryDef != null) {
          FileInputStream fin = new FileInputStream((File) dd.getFormValue("filename"));
          FileOutputStream fout = new FileOutputStream(queryDef.getTemplateFile());
          try {
            StreamUtils.copy(fin, fout);
          } finally {
            fin.close();
            fout.close();
          }
          out.write("打印模板\"" + queryDef.getTemplateFile().getName() + "\"已保存到服务器"
              + dd.getRequest().getServerName());
        } else {
          out.write("找不到对应的查询定义。");
        }
      } else {
        out.write("找不到指定的查询结果。");
      }
    } catch (Exception e) {
      out.write("错误:" + e.getMessage());
      Logger.getLogger(this.getClass()).error("saveReport", e);
    }
    return ActionConstants.DIRECT;
  }

  /**
   * 返回Zip压缩的查询结果集. get startnode=getData&qrdUuid=xxx
   * 
   * @return
   * @throws Exception
   */
  public String getData() throws Exception {
    IQueryResultMgr qrm = (IQueryResultMgr) NamingMgr.getInstance()
        .lookupMgr(IQueryResultMgr.class);
    IQueryDefinitionMgr qdm = (IQueryDefinitionMgr) NamingMgr.getInstance().lookupMgr(
        IQueryDefinitionMgr.class);
    String qrdUuid = (String) dd.getFormValue("qrdUuid");
    if (qrdUuid == null || qrdUuid.length() == 0)
      throw new Exception("指定的参数qrdUuid不能为空。");
    QueryResultDescription qrd = (QueryResultDescription) qrm.findQrdByUuid(qrdUuid);
    if (qrd == null)
      throw new Exception("找不到指定的查询结果(qrdUuid=" + qrdUuid + ")。");
    QueryDefinition qd = qdm.getQueryDefinition(qrd);
    if (qd == null)
      throw new Exception("找不到对应的查询定义。");
    SQLSubquery sq = new SQLSubquery();
    sq.addSelect("*");
    sq.addFrom(qrd.getTableName());
    for (int i = 0; i < qrd.getDisplayCriteria().getOrders().size(); ++i) {
      SQLOrder o = (SQLOrder) qrd.getDisplayCriteria().getOrders().get(i);
      sq.addOrder(o.getColumn(), o.getOrder());
    }
    Connection conn = null;
    Statement stm = null;
    ResultSet rs = null;

    File dir = new File(JspLib.getTempExportDir(dd.getRequest()));
    dir.mkdirs();
    File file = new File(dir, StringUtil.createUuid() + ".xml");
    FileOutputStream out = new FileOutputStream(file);
    try {
      out.write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>".getBytes());
      try {
        conn = QueryResultSession.getSession().connection();
      } catch (HibernateException e) {
        throw new MaxQueryException(e);
      }
      stm = conn.createStatement();
      rs = stm.executeQuery(sq.getSqlStatement());
      List titles = qd.getColumns().getVisibleColumnTitles();
      MidasUtil.resultSet2DataPacket(rs, out, titles);
    } finally {
      if (rs != null)
        rs.close();
      if (stm != null)
        stm.close();
      out.close();
    }

    File zfile = new File(dir, file.getName() + ".zip");
    compressFile(file, zfile);

    dd.getResponse().setCharacterEncoding("utf-8");
    sendFile(dd.getResponse(), zfile);
    file.delete();
    zfile.delete();

    return ActionConstants.DIRECT;
  }

  private void sendFile(HttpServletResponse response, File file) throws IOException {
    FileInputStream in = new FileInputStream(file);
    response.setContentLength((int) file.length());
    OutputStream out = response.getOutputStream();
    try {
      StreamUtils.copy(in, out);
    } finally {
      in.close();
    }
  }

  private void compressFile(File file, File compressedFile) throws Exception {
    try {
      FileOutputStream fout = new FileOutputStream(compressedFile);
      ZipOutputStream zout = new ZipOutputStream(fout);
      zout.putNextEntry(new ZipEntry(file.getName()));
      FileInputStream fin = new FileInputStream(file);
      StreamUtils.copy(fin, zout);
      fin.close();
      zout.closeEntry();
      zout.close();
    } catch (IOException e) {
      throw new Exception("压缩文件出错：" + e);
    }
  }
}
